home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 2.iso
/
STUTTGART
/
LANG
/
C
/
LIB
/
UNIXLIB37B
/
!UnixLib37
/
src
/
stdio
/
c
/
print
< prev
next >
Wrap
Text File
|
1996-11-09
|
20KB
|
1,083 lines
/****************************************************************************
*
* $Source: /unixb/home/unixlib/source/unixlib37/src/stdio/c/RCS/print,v $
* $Date: 1996/10/30 21:59:00 $
* $Revision: 1.3 $
* $State: Rel $
* $Author: unixlib $
*
* $Log: print,v $
* Revision 1.3 1996/10/30 21:59:00 unixlib
* Massive changes made by Nick Burret and Peter Burwood.
*
* Revision 1.2 1996/05/06 09:01:34 unixlib
* Updates to sources made by Nick Burrett, Peter Burwood and Simon Callan.
* Saved for 3.7a release.
*
* Revision 1.1 1996/04/19 21:32:42 simon
* Initial revision
*
***************************************************************************/
static const char rcs_id[] = "$Id: print,v 1.3 1996/10/30 21:59:00 unixlib Rel $";
/* Implements __printf(buf,format,argp) which is called by
* all printf() functions to perform formatted output. */
/* A conversion is of the form "%[flags][width][.prec][size]function".
* For full details RTFM for printf(3). */
#include <sys/syslib.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <float.h>
__STDIOLIB__
/* To avoid truncation PRBUFSIZ should be 256+.
* This library will *not* buffer overflow unless PRBUFSIZ < 4.
* ANSI requires at least 509 - 512 sounds sensible (SJC). */
#define PRBUFSIZ 4096
/* The floating point functions are the most efficient they can be without
* resorting to assuming IEEE 'D' or some other internal representation. */
/* Unfortunately most software FP units are *inaccurate* - it
* is probably worth changing these constants for architectures
* with built in hardware FP units - make MAXPREC larger &
* FPERR smaller for higher quality. Note that MAXPREC = 16
* corresponds to the limits of IEEE Packed Decimal format. */
#define MAXPREC 16 /* max. decimal precision for %feEgG */
#define FPERR 2*DBL_EPSILON /* cutoff value for zero test */
/* It's probably best to leave POINT alone... It works. - WRONG */
#define POINT DBL_EPSILON /* offset to compensate for rounding errors */
/* the prototypes for the output functions */
static char *__p_nout (char *, va_list *);
static char *__p_char (char *, va_list *);
static char *__p_str (char *, va_list *);
static char *__p_sdec (char *, va_list *);
static char *__p_uoct (char *, va_list *);
static char *__p_udec (char *, va_list *);
static char *__p_uhex (char *, va_list *);
static char *__p_ffix (char *, va_list *);
static char *__p_fexp (char *, va_list *);
static char *__p_fmin (char *, va_list *);
static char *__p_ptr (char *, va_list *);
/* the buffer __prpad has to be prior to __prbuf in memory -
* __prjust() avoids having to do any buffer copying by being
* able to back into the __prpad area from __prbuf */
static char __prpad[(PRBUFSIZ << 1) + 2];
static char *__prbuf = __prpad + PRBUFSIZ + 1;
/* __prebuf is set to the start of the output buffer passed to __printf() and
* is used by __p_nout() to calculate the number of characters output */
static char *__prebuf;
#define P_FLAG0 0x0001 /* '-' */
#define P_FLAG1 0x0002 /* '0' */
#define P_FLAG2 0x0004 /* '+' */
#define P_FLAG3 0x0008 /* ' ' */
#define P_FLAG4 0x0010 /* '#' */
#define P_FLAG5 0x0020 /* 'h' */
#define P_FLAG6 0x0040 /* 'l' */
#define P_FLAG7 0x0080 /* 'L' */
static int __prflag;
static unsigned int __prwidth; /* width */
static int __prprec; /* -1 = unspecified; precision */
static char __prfc; /* function character */
static signed char __prfnc[32] = /* conversions */
{
-1, -1,
1, /* %c */
3, /* %d */
9, /* %eE */
8, /* %f */
10, /* %gG */
-1,
4, /* %i */
-1, -1, -1, -1,
0, /* %n */
5, /* %o */
11, /* %p */
-1, -1,
2, /* %s */
-1,
6, /* %u */
-1, -1,
7, /* %xX */
-1, -1, -1, -1, -1, -1, -1, -1
};
/* __prfn[] is the array of output functions called by __printf() -
* they return a pointer to the end of the string (which is *not*
* necessarily 0 terminated) */
static char *(*__prfn[]) (char *, va_list *) =
{
__p_nout, /* %n no. of characters output so far */
__p_char, /* %c character */
__p_str, /* %s string */
__p_sdec, /* %d signed decimal */
__p_sdec, /* %i signed decimal */
__p_uoct, /* %o unsigned octal */
__p_udec, /* %u unsigned decimal */
__p_uhex, /* %xX unsigned hex */
__p_ffix, /* %f fixed notation double */
__p_fexp, /* %eE exponential notation double */
__p_fmin, /* %gG minimised space notation double */
__p_ptr /* %p unsigned hex value of pointer */
};
/* __printf() */
int
__printf (char *buf, const char *format, va_list ap)
{
register const char *s1 = format;
register char *s2 = buf;
__prebuf = buf; /* for __p_nout() */
while (*s1)
{
if (*s1 != '%' || *++s1 == '%') /* left to right evaluation */
{
*s2++ = *s1++;
continue;
}
{ /* we now have a % conversion */
register int i;
char *s;
/* looking for "%[flags][width][.prec][size]function" */
/* set flags */
__prflag = 0;
flag:
if (*s1 == '-')
{
__prflag |= P_FLAG0, s1++;
goto flag;
}
if (*s1 == '0')
{
__prflag |= P_FLAG1, s1++;
goto flag;
}
if (*s1 == '+')
{
__prflag |= P_FLAG2, s1++;
goto flag;
}
if (*s1 == ' ')
{
__prflag |= P_FLAG3, s1++;
goto flag;
}
if (*s1 == '#')
{
__prflag |= P_FLAG4, s1++;
goto flag;
}
/* set __prwidth */
__prwidth = 0;
if (isdigit (*s1))
{
__prwidth = (unsigned int) strtoul (s1, &s, 0);
s1 = s;
}
else
{
if (*s1 == '*')
{
int tmpwidth;
tmpwidth = va_arg (ap, int);
if (tmpwidth < 0)
{
__prflag |= P_FLAG0;
tmpwidth = -tmpwidth;
}
__prwidth = tmpwidth;
s1++;
}
}
if (__prwidth > PRBUFSIZ)
__prwidth = PRBUFSIZ;
/* set __prprec */
__prprec = -1;
if (*s1 == '.')
{
s1++;
if (isdigit (*s1))
{
__prprec = (int) strtol (s1, &s, 0);
s1 = s;
}
else
{
if (*s1 == '*')
{
__prprec = va_arg (ap, int);
s1++;
}
}
}
/* set size */
if (*s1 == 'h')
__prflag |= P_FLAG5, s1++;
else if (*s1 == 'l')
__prflag |= P_FLAG6, s1++;
else if (*s1 == 'L')
__prflag |= P_FLAG7, s1++;
/* call appropriate output function */
i = __prfnc[(_tolower (*s1) - 'a') & 31];
if (i >= 0)
{
__prfc = *s1;
s2 = __funcall ((*__prfn[i]), (s2, (va_list *) (&ap)));
}
s1++;
}
}
*s2 = 0;
return ((size_t) (s2 - buf)); /* number of characters output */
}
/* __prjust() */
/* __prjust() justifies the string at __prbuf according to __prwidth etc.
* it's argument is the *end* of the string at __prbuf - it returns the
* start of the justified string. */
static char *
__prjust (register char *e)
{
register char *s1, *s2;
register char p;
s1 = __prbuf;
p = (__prflag & P_FLAG1) ? '0' : ' ';
if (__prflag & P_FLAG0)
{
s2 = s1 + __prwidth;
while (e < s2)
*e++ = ' ';
*e = 0;
return (s1);
}
else
{
if ((e -= __prwidth) < s1)
{
s2 = e;
while (e < s1)
*e++ = p;
return (s2);
}
return (s1);
}
}
/* __prdec() */
/* __prdec() is a subroutine (called by __p_...() functions) that writes
* a decimal number <x> backwards from <e> towards <b>, digit by digit.
If pad is set true then numbers 0<=x<=9 are prefixed with a zero.
The pad is only needed by the exponential print functions to comply
with ANSI standards. */
static char *
__prdec (register char *b, register char *e, register unsigned int x, int pad)
{
*e = 0;
if (pad)
pad = (x <= 9) ? 1 : 0;
do
{
*--e = (x % 10) + '0';
x /= 10;
}
while (x && e > b);
if (pad)
*--e = '0';
return (e);
}
/* __prexp() */
/* __prexp() normalises <x> to a number of the form n.nnnn...
* and stores the exponent in *<e> */
static double
__prexp (register double x, register int *e)
{
register int h;
h = 0;
if (x != 0)
{
if (x >= 10)
{
register double l = 0, m = 10;
while (x >= m)
{
l = m, m *= 10;
h++;
}
if (l)
x /= l;
}
else
{
while (x < 1)
{
x *= 10;
h--;
}
}
}
/* x is now n.nnnn... */
*e = h;
return (x);
}
/* __p_nout() */
static char *
__p_nout (register char *s, register va_list * ap) /* %n */
{
if (__prflag & P_FLAG5)
*va_arg (*ap, short *) = (short) (s - __prebuf);
else if (__prflag & P_FLAG6)
*va_arg (*ap, long *) = (long) (s - __prebuf);
else
*va_arg (*ap, int *) = (int) (s - __prebuf);
return (s);
}
/* __p_char() */
static char *
__p_char (register char *s, register va_list * ap) /* %c */
{
register char *b;
if (!__prwidth)
*s++ = va_arg (*ap, char);
else
{
b = __prbuf;
*b++ = va_arg (*ap, char);
*b = 0;
b = __prjust (b);
while (*s = *b)
s++, b++;
}
return (s);
}
/* __p_str() */
static char *
__p_str (register char *s, register va_list * ap) /* %s */
{
register char *_s;
register char *b, *e;
register int p;
p = (__prprec < 0) ? PRBUFSIZ : __prprec;
if (p > PRBUFSIZ)
p = PRBUFSIZ;
_s = va_arg (*ap, char *);
/* tolerance */
if (!_s)
_s = __null;
/* fast output if no width specified */
if (!__prwidth)
{
e = s + p;
while ((s < e) && (*s = *_s))
s++, _s++;
return (s);
}
e = (b = __prbuf) + p;
while (b < e && (*b = *_s))
b++, _s++;
*b = 0;
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_sdec() */
static char *
__p_sdec (register char *s, register va_list * ap) /* %d */
{
register int x, n;
register char *b, *e;
register int p;
p = (__prprec < 0) ? 0 : __prprec;
if (p > PRBUFSIZ - 2)
p = PRBUFSIZ - 2;
if (__prflag & P_FLAG5)
n = (int) va_arg (*ap, short);
else if (__prflag & P_FLAG6)
n = (int) va_arg (*ap, long);
else
n = va_arg (*ap, int);
x = (n < 0) ? (-n) : n;
b = __prbuf;
e = b + PRBUFSIZ;
if ((__prflag & P_FLAG2) || (n < 0))
*b++ = (n < 0) ? '-' : '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
e = __prdec (b, e, (unsigned int) x, 0);
if (p)
{
x = p - strlen (e);
while (x > 0)
{
*b++ = '0';
x--;
}
}
while (*b = *e)
b++, e++;
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_uoct() */
static char *
__p_uoct (register char *s, register va_list * ap) /* %o */
{
register unsigned int x, n;
register char *b, *e;
register int p;
p = (__prprec < 0) ? 0 : __prprec;
if (p > PRBUFSIZ - 3)
p = PRBUFSIZ - 3;
if (__prflag & P_FLAG5)
n = (unsigned int) va_arg (*ap, unsigned short);
else if (__prflag & P_FLAG6)
n = (unsigned int) va_arg (*ap, unsigned long);
else
n = va_arg (*ap, unsigned int);
x = n;
b = __prbuf;
*(e = (b + PRBUFSIZ)) = 0;
do
{
*--e = (x & 7) + '0';
x >>= 3;
}
while (b < e && x);
if (__prflag & P_FLAG2)
*b++ = '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
if (__prflag & P_FLAG4)
*b++ = '0';
if (p)
{
x = p - strlen (e);
while (x > 0)
{
*b++ = '0';
x--;
}
}
while (*b = *e)
b++, e++;
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_udec() */
static char *
__p_udec (register char *s, register va_list * ap) /* %u */
{
register unsigned int x, n;
register char *b, *e;
register int p;
p = (__prprec < 0) ? 0 : __prprec;
if (p > PRBUFSIZ - 2)
p = PRBUFSIZ - 2;
if (__prflag & P_FLAG5)
n = (unsigned int) va_arg (*ap, unsigned short);
else if (__prflag & P_FLAG6)
n = (unsigned int) va_arg (*ap, unsigned long);
else
n = va_arg (*ap, unsigned int);
x = n;
b = __prbuf;
e = b + PRBUFSIZ;
if (__prflag & P_FLAG2)
*b++ = '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
e = __prdec (b, e, x, 0);
if (p)
{
x = p - strlen (e);
while (x > 0)
{
*b++ = '0';
x--;
}
}
while (*b = *e)
b++, e++;
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_uhex() */
static char *
__p_uhex (register char *s, register va_list * ap) /* %xX */
{
register unsigned int x, n;
register char *b, *e;
register char *hex;
register int p;
p = (__prprec < 0) ? 0 : __prprec;
if (p > PRBUFSIZ - 4)
p = PRBUFSIZ - 4;
hex = (__prfc == 'X') ? "0123456789ABCDEF" : "0123456789abcdef";
if (__prflag & P_FLAG5)
n = (unsigned int) va_arg (*ap, unsigned short);
else if (__prflag & P_FLAG6)
n = (unsigned int) va_arg (*ap, unsigned long);
else
n = va_arg (*ap, unsigned int);
x = n;
b = __prbuf;
*(e = (b + PRBUFSIZ)) = 0;
do
{
*--e = hex[x & 15];
x >>= 4;
}
while (b < e && x);
if (__prflag & P_FLAG2)
*b++ = '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
if ((__prflag & P_FLAG4) && n)
{
*b++ = '0';
*b++ = 'x';
}
if (p)
{
x = p - strlen (e);
while (x > 0)
{
*b++ = '0';
x--;
}
}
while (*b = *e)
b++, e++;
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_ffix() */
static char *
__p_ffix (register char *s, register va_list * ap) /* %f */
{
const double point = POINT;
const double err = FPERR;
register double x, n, w;
register unsigned int i;
int h;
register int p, m;
register char *b, *e;
if (__prflag & P_FLAG7)
n = (double) va_arg (*ap, long double);
else
n = va_arg (*ap, double);
b = __prbuf;
e = b + PRBUFSIZ;
if ((__prflag & P_FLAG2) || (n < 0))
*b++ = (n < 0) ? '-' : '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
x = (n < 0) ? (-n) : n;
x = __prexp (x, &h);
w = 1;
while (h < 0)
{
w *= 10;
h++;
}
x /= w;
/* integer part - ensure at least 1 digit */
do
{
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
h--;
}
while (b < e && h >= 0 && x > err);
while (b < e && h >= 0)
{
*b++ = '0';
h--;
}
m = (__prprec < 0) ? 6 : __prprec;
p = (m > MAXPREC) ? MAXPREC : m;
m -= p;
/* fractional part */
if (p || (__prflag & P_FLAG4))
{
if (b < e)
*b++ = '.';
while (b < e && p && x > err)
{
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
p--;
}
while (p && b < e)
{
*b++ = '0';
p--;
}
while (m && b < e)
{
*b++ = '0';
m--;
}
}
*b = 0;
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_fexp() */
static char *
__p_fexp (register char *s, register va_list * ap) /* %eE */
{
const double point = POINT;
const double err = FPERR;
register double x, n;
register unsigned int i;
int h;
register int p, m;
register char *b, *e;
if (__prflag & P_FLAG7)
n = (double) va_arg (*ap, long double);
else
n = va_arg (*ap, double);
b = __prbuf;
e = b + PRBUFSIZ;
if ((__prflag & P_FLAG2) || (n < 0))
*b++ = (n < 0) ? '-' : '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
x = (n < 0) ? (-n) : n;
x = __prexp (x, &h);
m = (__prprec < 0) ? 6 : __prprec;
p = (m > MAXPREC) ? MAXPREC : m;
m -= p;
/* 1 digit before decimal point */
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
/* fractional part */
if (p || (__prflag & P_FLAG4))
{
if (b < e)
*b++ = '.';
while (b < e && p && x > err)
{
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
p--;
}
while (p && b < e)
{
*b++ = '0';
p--;
}
while (m && b < e)
{
*b++ = '0';
m--;
}
}
/* exponent */
if (b < e)
*b++ = __prfc;
if (b < e)
*b++ = (h < 0) ? '-' : '+';
if (b < e)
e = __prdec (b, e, (h < 0) ? (unsigned int) (-h) : (unsigned int) h, 1);
while (*b = *e)
b++, e++;
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_fmin() */
static char *
__p_fmin (register char *s, register va_list * ap) /* %gG */
{
const double point = POINT;
const double err = FPERR;
register double x, n, w;
register unsigned int i;
int h;
register int p, m;
register char *b, *e;
if (__prflag & P_FLAG7)
n = (double) va_arg (*ap, long double);
else
n = va_arg (*ap, double);
b = __prbuf;
e = b + PRBUFSIZ;
if ((__prflag & P_FLAG2) || (n < 0))
*b++ = (n < 0) ? '-' : '+';
else if (__prflag & P_FLAG3)
*b++ = ' ';
/* %gG count significant figures of precision, not decimal places.
* For %e we decrement the precision (for the digit before the decimal point).
* For %f we subtract the exponent from the precision. */
m = (__prprec < 0) ? 6 : __prprec;
p = (m > MAXPREC) ? MAXPREC : m;
m -= p;
x = (n < 0) ? (-n) : n;
x = __prexp (x, &h);
/* "The style used depends on the value converted; style %e will be used
* only if the exponent resulting from the conversion is less than -4 or
* greater than the precision." - ANSI X3J11 */
if (h < -4 || h > p) /* %e */
{
if (p)
p--; /* just in case */
/* 1 digit before decimal point */
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
/* fractional part */
if (p || (__prflag & P_FLAG4))
{
if (b < e)
*b++ = '.';
while (b < e && p && x > err)
{
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
p--;
}
if (__prflag & P_FLAG4)
{
while (p && b < e)
{
*b++ = '0';
p--;
}
while (m && b < e)
{
*b++ = '0';
m--;
}
}
else if (b < e) /* waste trailing 0s */
{
while (*--b == '0');
b++;
if (*--b != '.')
b++;
}
}
/* exponent */
if (b < e)
*b++ = __prfc - ('g' - 'e');
if (b < e)
*b++ = (h < 0) ? '-' : '+';
if (b < e)
e = __prdec (b, e, (h < 0) ? (unsigned int) (-h) : (unsigned int) h, 1);
while (*b = *e)
b++, e++;
}
else
/* %f */
{
w = 1;
while (h < 0)
{
w *= 10;
h++;
}
x /= w;
p -= h;
/* integer part - ensure at least 1 digit */
do
{
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
h--;
}
while (b < e && h >= 0 && x > err);
while (b < e && h >= 0)
{
*b++ = '0';
h--;
}
/* fractional part */
if (p || (__prflag & P_FLAG4))
{
if (b < e)
*b++ = '.';
while (b < e && p && x > err)
{
x = (x - (double) (i = (unsigned int) (x + point))) * 10;
*b++ = i + '0';
p--;
}
if (__prflag & P_FLAG4)
{
while (p && (b < e))
{
*b++ = '0';
p--;
}
while (m && (b < e))
{
*b++ = '0';
m--;
}
}
else if (b < e) /* waste trailing 0s */
{
while (*--b == '0');
b++;
if (*--b != '.')
b++;
}
}
*b = 0;
}
if (!__prwidth)
b = __prbuf;
else
b = __prjust (b);
while (*s = *b)
s++, b++;
return (s);
}
/* __p_ptr() */
static char *
__p_ptr (register char *s, register va_list * ap) /* %p */
{
__prflag |= P_FLAG4;
return (__p_uhex (s, ap));
}